package app.ep1.portoes;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.widget.LinearLayout;
import android.widget.TextView;
import app.ep1.R;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;

public class PortoesActivity extends MapActivity {

	LinearLayout linearLayout;
	MapView mapView;
	private Road mRoad1;
	private Road mRoad2;
	private Road mRoad3;

	private GeoPoint p1;
	private GeoPoint p2;
	private GeoPoint p3;
	private GeoPoint filaP1Sair;
	private GeoPoint filaP2Sair;
	private GeoPoint filaP3Sair;
	private GeoPoint ime;
	private GeoPoint down;
	private GeoPoint up;

	private boolean isClick;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.portoes);
		mapView = (MapView) findViewById(R.id.mapview);
		mapView.setBuiltInZoomControls(true);

		p1 = new GeoPoint(-23565590, -46711840);
		p2 = new GeoPoint(-23550615, -46732455);
		p3 = new GeoPoint(-23569240, -46741390);
		filaP1Sair = new GeoPoint(-23565590, -46711840);
		filaP2Sair = new GeoPoint(-23550615, -46732455);
		filaP3Sair = new GeoPoint(-23569240, -46741390);
		ime = new GeoPoint(-23558100, -46731800);
		MapController mapController = mapView.getController();
		mapController.animateTo(ime);
		mapController.setZoom(15);

		isClick = false;

		pegaFilasJaCadastradas();

		drawRoute();
		TextView textView = (TextView) findViewById(R.id.description);
		textView.setText("Mostre no mapa o ponto onde o seu carro parou devido ao trânsito");
	}

	public void pegaFilasJaCadastradas() {
		GeoPoint aux;

		aux = achaFimDaFila(1);
		if (aux != null)
			filaP1Sair = aux;

		aux = achaFimDaFila(2);
		if (aux != null)
			filaP2Sair = aux;

		aux = achaFimDaFila(3);
		if (aux != null)
			filaP3Sair = aux;
	}

	public GeoPoint getFilaP1Sair() {
		return filaP1Sair;
	}

	public GeoPoint getFilaP2Sair() {
		return filaP2Sair;
	}

	public GeoPoint getFilaP3Sair() {
		return filaP3Sair;
	}

	private GeoPoint achaFimDaFila(int portao) {
		HttpClient httpClient = new DefaultHttpClient();

		HttpGet httpGet = new HttpGet(
				"http://valinhos.ime.usp.br:56080/usp-mobile/portao/" + portao
						+ "/SAINDO");

		HttpResponse httpResponse;
		JSONObject jsonObject = null;

		try {
			httpResponse = httpClient.execute(httpGet);

			HttpEntity httpEntity = httpResponse.getEntity();

			if (httpEntity != null) {
				InputStream inputStream = httpEntity.getContent();
				String result = streamToString(inputStream);

				if (result != "")
					jsonObject = new JSONObject(result);

				inputStream.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		GeoPoint geoPoint = null;

		try {
			JSONArray jsonArray = jsonObject.getJSONArray("list");

			if (jsonArray.length() <= 0)
				return null;

			for (int i = jsonArray.length() - 1; i >= 0; i--) {
				JSONObject json = jsonArray.getJSONObject(i);

				Double latitude = json.optDouble("latitude");
				Double longitude = json.optDouble("longitude");

				if (!latitude.isNaN() && !longitude.isNaN()) {
					geoPoint = new GeoPoint((int) (latitude * 1E6),
							(int) (longitude * 1E6));

					break;
				}
			}

		} catch (JSONException e) {
			e.printStackTrace();
		}

		return geoPoint;
	}

	private static String streamToString(InputStream inputStream) {
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				inputStream));
		StringBuilder stringBuilder = new StringBuilder();

		String line = null;

		try {
			while ((line = reader.readLine()) != null)
				stringBuilder.append(line + "\n");
		} catch (Exception e) {
			e.printStackTrace();
		}

		return stringBuilder.toString();
	}

	void drawRoute() {
		new Thread() {
			@Override
			public void run() {
				double fromLat, fromLon, toLat, toLon;
				fromLat = (double) (filaP1Sair.getLatitudeE6()) / 1000000;
				fromLon = (double) (filaP1Sair.getLongitudeE6()) / 1000000;
				toLat = (double) (p1.getLatitudeE6()) / 1000000;
				toLon = (double) (p1.getLongitudeE6()) / 1000000;
				String url = RoadProvider
						.getUrl(fromLat, fromLon, toLat, toLon);
				InputStream is = getConnection(url);
				mRoad1 = RoadProvider.getRoute(is);

				fromLat = (double) (filaP2Sair.getLatitudeE6()) / 1000000;
				fromLon = (double) (filaP2Sair.getLongitudeE6()) / 1000000;
				toLat = (double) (p2.getLatitudeE6()) / 1000000;
				toLon = (double) (p2.getLongitudeE6()) / 1000000;
				url = RoadProvider.getUrl(fromLat, fromLon, toLat, toLon);
				is = getConnection(url);
				mRoad2 = RoadProvider.getRoute(is);

				fromLat = (double) (filaP3Sair.getLatitudeE6()) / 1000000;
				fromLon = (double) (filaP3Sair.getLongitudeE6()) / 1000000;
				toLat = (double) (p3.getLatitudeE6()) / 1000000;
				toLon = (double) (p3.getLongitudeE6()) / 1000000;
				url = RoadProvider.getUrl(fromLat, fromLon, toLat, toLon);
				is = getConnection(url);
				mRoad3 = RoadProvider.getRoute(is);

				mHandler.sendEmptyMessage(0);
			}
		}.start();
	}

	Handler mHandler = new Handler() {
		public void handleMessage(android.os.Message msg) {
			/*
			 * TextView textView1 = (TextView) findViewById(R.id.description);
			 * textView1.setText(mRoad1.mName + " " + mRoad1.mDescription);
			 */
			MapOverlay mapOverlay1 = new MapOverlay(mRoad1, mapView);
			MapOverlay mapOverlay2 = new MapOverlay(mRoad2, mapView);
			MapOverlay mapOverlay3 = new MapOverlay(mRoad3, mapView);
			List<Overlay> listOfOverlays = mapView.getOverlays();
			listOfOverlays.clear();
			listOfOverlays.add(mapOverlay1);
			listOfOverlays.add(mapOverlay2);
			listOfOverlays.add(mapOverlay3);
			mapView.invalidate();
		};
	};

	private InputStream getConnection(String url) {
		InputStream is = null;
		try {
			URLConnection conn = new URL(url).openConnection();
			is = conn.getInputStream();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return is;
	}

	double dist(GeoPoint p, GeoPoint q) {
		return (p.getLatitudeE6() - q.getLatitudeE6())
				* (p.getLatitudeE6() - q.getLatitudeE6())
				+ (p.getLongitudeE6() - q.getLongitudeE6())
				* (p.getLongitudeE6() - q.getLongitudeE6());
	}

	private void atualizaPosicaoDaFila() {
		double d1 = dist(up, p1);
		double d2 = dist(up, p2);
		double d3 = dist(up, p3);
		int portao;

		if (d1 < d2) {
			if (d1 < d3) {
				filaP1Sair = up;
				portao = 1;
			} else {
				filaP3Sair = up;
				portao = 3;
			}
		} else {
			if (d2 < d3) {
				filaP2Sair = up;
				portao = 2;
			} else {
				filaP3Sair = up;
				portao = 3;
			}
		}

		drawRoute();
		enviaPosicaoDaFila(portao, up);
	}

	private void enviaPosicaoDaFila(int portao, GeoPoint geoPoint) {
		HttpClient httpClient = new DefaultHttpClient();
		HttpPost httpPost = new HttpPost(
				"http://valinhos.ime.usp.br:56080/usp-mobile/portao/" + portao
						+ "/SAINDO");

		Double longitude = geoPoint.getLongitudeE6() / 1E6;
		Double latitude = geoPoint.getLatitudeE6() / 1E6;

		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		nameValuePairs.add(new BasicNameValuePair("comentario.longitude",
				longitude.toString()));
		nameValuePairs.add(new BasicNameValuePair("comentario.latitude",
				latitude.toString()));

		try {
			httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}

		try {
			httpClient.execute(httpPost);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}

	public boolean isDentroUsp(GeoPoint geoPoint) {
		int latitude = geoPoint.getLatitudeE6();
		int longitude = geoPoint.getLongitudeE6();

		if (latitude <= -23550000 && latitude >= -23574000
				&& longitude <= -46710000 && longitude >= -46748000)
			return true;

		return false;
	}

	class MapOverlay extends com.google.android.maps.Overlay {
		Road mRoad;
		ArrayList<GeoPoint> mPoints;

		public MapOverlay(Road road, MapView mv) {
			mRoad = road;
			if (road.mRoute.length > 0) {
				mPoints = new ArrayList<GeoPoint>();
				for (int i = 0; i < road.mRoute.length; i++) {
					mPoints.add(new GeoPoint(
							(int) (road.mRoute[i][1] * 1000000),
							(int) (road.mRoute[i][0] * 1000000)));
				}
			}
		}

		@Override
		public boolean onTouchEvent(MotionEvent event, MapView mapview) {

			if (event.getAction() == MotionEvent.ACTION_DOWN) {
				isClick = true;
				down = mapview.getProjection().fromPixels((int) event.getX(),
						(int) event.getY());
			} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
				isClick = false;
			} else if (event.getAction() == MotionEvent.ACTION_UP && isClick) {
				isClick = false;
				up = mapview.getProjection().fromPixels((int) event.getX(),
						(int) event.getY());

				if (dist(up, down) < 5 && isDentroUsp(up)) {
					AlertDialog.Builder builder = new AlertDialog.Builder(
							PortoesActivity.this);
					builder.setMessage("Voce tem certeza?")
							.setCancelable(false)
							.setPositiveButton("Sim",
									new DialogInterface.OnClickListener() {
										public void onClick(
												DialogInterface dialog, int id) {
											PortoesActivity.this
													.atualizaPosicaoDaFila();
										}
									})
							.setNegativeButton("Nao",
									new DialogInterface.OnClickListener() {
										public void onClick(
												DialogInterface dialog, int id) {
											dialog.cancel();
										}
									}).show();

				}
			}

			return false;
		}

		@Override
		public boolean draw(Canvas canvas, MapView mv, boolean shadow, long when) {
			super.draw(canvas, mv, shadow);
			drawPath(mv, canvas);
			return true;
		}

		public void drawPath(MapView mv, Canvas canvas) {
			int x1 = -1, y1 = -1, x2 = -1, y2 = -1;
			Paint paint = new Paint();
			paint.setColor(Color.RED);
			paint.setStyle(Paint.Style.STROKE);
			paint.setStrokeWidth(3);
			for (int i = 0; i < mPoints.size(); i++) {
				Point point = new Point();
				mv.getProjection().toPixels(mPoints.get(i), point);
				x2 = point.x;
				y2 = point.y;
				if (i > 0) {
					canvas.drawLine(x1, y1, x2, y2, paint);
				}
				x1 = x2;
				y1 = y2;
			}
		}
	}
}